/**
 * Режим работы: без добавления элементов.
 * @type {number}
 */
var NONE   = 0;

/**
 * Режим работы: добавление объекта на сцену.
 * @type {number}
 */
var OBJECT = 1;

/**
 * Режим работы: создание связей между объектами.
 * @type {number}
 */
var LINK   = 2;

/**
 * Режим работы: удаление объекта.
 * @type {number}
 */
var REMOVE = 3;

/**
 * Конструктор класса модели сцены.
 * @param canvas Контекст рисования.
 * @param height Длина сцены.
 * @param width Ширина сцены.
 * @constructor
 */
function DiagramScene (canvas, height, width) {
    this.objects = new Array();
    this.connects = new Array();
    this.height = height; //480;
    this.width = width; //640;
    this.scene = canvas;
    this.mode = NONE;
    this.first = null;

    // Формирование меню
    this.bottomMenu = new BottomMenu();

    // Задать размеры сцены
    this.scene.width = this.width;
    this.scene.height = this.height;

    // Подключение события: перемещение мыши над сценой
    var diagramScene = this;
    this.scene.addEventListener('mousemove', function(evt){
        diagramScene.mouseMove(evt);
    }, false);
}

/**
 * Метод обработки события: "Перемещение мыши по сцене"
 * @param evt Событие перемещения мыши.
 */
DiagramScene.prototype.mouseMove = function(evt) {
    var rect = this.scene.getBoundingClientRect();
    var x = evt.clientX - rect.left;
    var y = evt.clientY - rect.top;

    if (this.height - y <= 30) {
        console.log('show bottom menu');
    }
};

/**
 * Метод изменения ширины сцены.
 * @param width Новое значение ширины сцены.
 */
DiagramScene.prototype.setWidth = function(width) {
    this.width = width;
    this.scene.width = this.width;
};

/**
 * Метод изменения длины сцены.
 * @param height Новое значение длины сцены.
 */
DiagramScene.prototype.setHeight = function(height) {
    this.height = height;
    this.scene.height = this.height;
};

/**
 * Метод добавления объекта в модель.
 * @param obj Новый объект.
 */
DiagramScene.prototype.appendObject = function(obj) {
    this.objects.push(obj);
};

/**
 * Метод добавления связи в модель.
 * @param obj1 Объект источник.
 * @param obj2 Объект приемник.
 */
DiagramScene.prototype.appendConnect = function(obj1, obj2) {
    this.connects.push(new DiagramConnect(obj1, obj2));
};

/**
 * Метод обновления сцены.
 */
DiagramScene.prototype.update = function() {
    // Очистка сцены.
    var ctx = this.scene.getContext('2d');
    ctx.clearRect(0, 0, this.scene.width, this.scene.height);

    // Рисование объектов.
    for (var i = 0; i < this.objects.length; i++) {
        this.objects[i].draw(this.scene);
    }

    for (var i = 0; i < this.connects.length; i++) {
        this.connects[i].draw(this.scene);
    }
};

/**
 * Метод очистки сцены.
 */
DiagramScene.prototype.clear = function() {
    this.objects = new Array();
    this.connects = new Array();
    this.update();
};

/**
 * Метод получения выбранного объекта.
 * @returns {*} Выбранный объект или null.
 */
DiagramScene.prototype.getSelectedObject = function() {

    for (var i = 0; i < this.objects.length; i++) {
        if (this.objects[i].isSelected) {
            return this.objects[i];
        }
    }

    return null;
};

/**
 * Удаление объекта со сцены.
 */
DiagramScene.prototype.removeObject = function() {
    for (var i = 0; i < this.objects.length; i++) {
        if (this.objects[i].isSelected) {
            for (var j = 0; j < this.connects.length; j++) {
                if (this.connects[j].obj1 == this.objects[i] ||
                    this.connects[j].obj2 == this.objects[i]) {
                    this.connects.splice(j, 1);
                    j--;
                }
            }
            this.objects.splice(i, 1);
            break;
        }
    }
};

/**
 * Метод обработки клика.
 * @param data Данные события клика.
 */
DiagramScene.prototype.click = function(data) {
    var rect = this.scene.getBoundingClientRect();
    var x = data.clientX - rect.left;
    var y = data.clientY - rect.top;
    var isSelected = true;

    for (var i = 0; i < this.objects.length; i++) {
        isSelected *= this.objects[i].click(x, y);
    }

    if (this.mode == LINK) {
        this.constructLink();
    }

    if (this.mode == REMOVE) {
        this.removeObject();
    }

    if (isSelected) {
        this.constructObject(x, y);
    }

    this.update();
};

/**
 * Метод создания связи.
 */
DiagramScene.prototype.constructLink = function() {
    if (this.first == null) {
        this.first = this.getSelectedObject();
    } else {
        if (this.getSelectedObject() != null) {
            this.appendConnect(this.first, this.getSelectedObject());
            this.first = null;
        }
    }
};

/**
 * Метод создания объекта.
 * @param x Координата объекта x.
 * @param y Координата объекта y.
 */
DiagramScene.prototype.constructObject = function(x, y) {
    if (this.mode == OBJECT) {
        var obj = new DiagramObject('Object', x, y);
        this.appendObject(obj);
        this.mode = NONE;
    }
    this.first = null;
};

/**
 * Метод задания режима работы.
 * @param mode Режим работы.
 */
DiagramScene.prototype.setMode = function(mode) {
    // Если значение режима невенрно.
    if (mode < NONE || mode > REMOVE) return;
    this.mode = mode;
};

/**
 * Метод получения значения режима работы.
 * @returns {number|*} Значение режима работы.
 */
DiagramScene.prototype.getMode = function() {
    return this.mode;
};

/**
 * Метод преобразования сцены в картинку.
 * @returns {string} Ссылка на картинку.
 */
DiagramScene.prototype.toImage = function() {
    return this.scene.toDataURL();
};